home *** CD-ROM | disk | FTP | other *** search
- #include "protocol.h"
- #include "bootinc.h"
-
-
- #define IPPORT_TFTP 69
-
- #ifndef TFTP_TIMEOUT
- #define TFTP_TIMEOUT 5 /* secs between rexmt's */
- #endif
-
- #define SEGSIZE 512 /* data segment size */
-
- /*
- * Packet types.
- */
- #define RRQ 01 /* read request */
- #define WRQ 02 /* write request */
- #define DATA 03 /* data packet */
- #define ACK 04 /* acknowledgement */
- #define ERROR 05 /* error code */
-
- struct tftphdr
- {
- short th_opcode; /* packet type */
- union
- {
- short tu_block; /* block # */
- short tu_code; /* error code */
- char tu_stuff[1]; /* request packet stuff */
- } th_u;
- char th_data[1]; /* data or error string */
- };
-
- #define th_block th_u.tu_block
- #define th_code th_u.tu_code
- #define th_stuff th_u.tu_stuff
- #define th_msg th_data
-
- /*
- * Error codes.
- */
- #define EUNDEF 0 /* not defined */
- #define ENOTFOUND 1 /* file not found */
- #define EACCESS 2 /* access violation */
- #define ENOSPACE 3 /* disk full or allocation
- * exceeded */
- #define EBADOP 4 /* illegal TFTP operation */
- #define EBADID 5 /* unknown transfer ID */
- #define EEXISTS 6 /* file already exists */
- #define ENOUSER 7 /* no such user */
-
- #define PKTSIZE SEGSIZE+4
-
- static tftp_buffer[PKTSIZE];
-
- int
- makerequest(int request, char *name, struct tftphdr * tp)
- {
- register char *cp;
-
- tp->th_opcode = intswap((uint16) request);
- cp = tp->th_stuff;
- strcpy(cp, name);
- cp += strlen(name);
- *cp++ = '\0';
- strcpy(cp, "octet");
- cp += 5;
- *cp++ = '\0';
- return (cp - (char *) tp);
- }
-
- struct errmsg
- {
- int e_code;
- char *e_msg;
- } errmsgs[] =
-
- {
- { EUNDEF, "Undefined error code" },
- { ENOTFOUND, "File not found" },
- { EACCESS, "Access violation" },
- { ENOSPACE, "Disk full or allocation exceeded" },
- { EBADOP, "Illegal TFTP operation" },
- { EBADID, "Unknown transfer ID" },
- { EEXISTS, "File already exists" },
- { ENOUSER, "No such user" },
- { -1, 0 }
- };
-
- void
- tpacket(char *s, struct tftphdr * tp, int n)
- {
- static char *opcodes[] =
- {"#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR"};
- register char *cp,
- *file;
- uint16 op;
-
- op = intswap(tp->th_opcode);
-
- if (op < RRQ || op > ERROR)
- n_printf("%s opcode=%x ", s, op);
- else
- n_printf("%s %s ", s, opcodes[op]);
-
- switch (op)
- {
-
- case RRQ:
- case WRQ:
- n -= 2;
- file = cp = tp->th_stuff;
- cp = strchr(cp, '\0');
- n_printf("<file=%s, mode=%s>\n", file, cp + 1);
- break;
-
- case DATA:
- n_printf("<block=%d, %d bytes>\n", intswap(tp->th_block), n - 4);
- break;
-
- case ACK:
- n_printf("<block=%d>\n", intswap(tp->th_block));
- break;
-
- case ERROR:
- n_printf("<code=%d, msg=%s>\n", intswap(tp->th_code), tp->th_msg);
- break;
- }
- }
-
- /*
- * Receive a file.
- */
- int
- tftp_get(char *name)
- {
- struct tftphdr *ap;
- struct tftphdr *dp;
- int block;
- int size;
- int firsttrip;
- int port;
- unsigned long start_time;
- int ulen;
- int y;
- int retcode;
- int j;
- int delay;
- char c;
-
- block = 1;
- firsttrip = 1;
- port = IPPORT_TFTP;
- ap = (struct tftphdr *) tftp_buffer;
- dp = (struct tftphdr *) udp_rxdata.data;
- retcode = 0;
-
- while (1)
- {
- if (firsttrip)
- {
- size = makerequest(RRQ, name, ap);
- }
- else
- {
- ap->th_opcode = intswap((uint16) ACK);
- ap->th_block = intswap((uint16) (block));
- size = 4;
- block++;
- }
- send_ack:
- if (debug)
- tpacket("sending", ap, size);
- y = netusend(nnipserver, nnserveraddr, port, IPPORT_TFTP, (unsigned char *) ap, size);
- if (y)
- {
- return (y);
- }
- get_next:
- start_time = n_secs();
- delay = TFTP_TIMEOUT;
- while ((n_secs() - start_time) < (unsigned long) delay)
- {
- if (monitor_check() > 1)
- return 2000;
- ulen = udprecv(&udp_rxdata, IPPORT_TFTP);
- if (!ulen)
- continue; /* process all packets */
- if (ulen < 0)
- return -ulen;
- delay = 0;
- break;
- }
- if (delay)
- {
- retcode = 1020;
- goto abort;
- }
- if (firsttrip)
- {
- firsttrip = 0;
- port = intswap(udp_rxdata.u.source);
- }
- /* copy their port number, sice they may move it */
- if (debug)
- tpacket("received", dp, ulen);
- /* should verify client address */
- dp->th_opcode = intswap(dp->th_opcode);
- dp->th_block = intswap(dp->th_block);
- if (dp->th_opcode == ERROR)
- {
- n_printf("Tftp: %d: %s\n", dp->th_code, dp->th_msg);
- retcode = 1021;
- goto abort;
- }
- if (dp->th_opcode != DATA)
- {
- retcode = 1022;
- break;
- }
- n_printf("\rBlock %d", dp->th_block);
- if (dp->th_block != block)
- {
- n_printf("Missed something\n");
- /*
- * On an error, try to synchronize both sides.
- */
- for (j = 0; ; j++)
- {
- ulen = udprecv(&udp_rxdata, IPPORT_TFTP);
- if (ulen < 0)
- return -ulen;
- if (ulen == 0)
- break;
- }
- if (j && debug)
- {
- n_printf("discarded %d packets\n", j);
- }
- if (dp->th_block == (block - 1))
- {
- goto send_ack; /* resend ack */
- }
- goto get_next;
- }
- /* otherwise good */
- /* update data rxed , ulen - 4 len */
- size = ulen - 4;
- if (block == 1)
- {
- if (size < SEGSIZE)
- {
- c = dp->th_data[0];
- if (c == '\n' || c == '\r' ||
- (c >= ' ' && c < '\177'))
- {
- /* take a punt and call it ascii */
- n_printf("%s", dp->th_data);
- }
- retcode = 3000;
- break;
- }
- retcode = decode_header(dp->th_data);
- if (retcode)
- break;
- }
- else
- {
- if (size)
- {
- retcode = place_data(dp->th_data, size);
- if (retcode)
- break;
- }
- if (size < SEGSIZE)
- break;
- }
- continue;
- }
-
- abort:
- /* ok to ack, since user */
- ap->th_opcode = intswap((uint16) ACK); /* has seen err msg */
- ap->th_block = intswap((uint16) block);
- y = netusend(nnipserver, nnserveraddr, port, IPPORT_TFTP, (unsigned char *) ap, 4);
- return retcode;
- }
-